/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cn.zzdt4j.config.springboot.starter.config;

import cn.hutool.core.util.StrUtil;
import cn.zzdt4j.adapter.web.WebThreadPoolService;
import cn.zzdt4j.common.api.ThreadPoolConfigChange;
import cn.zzdt4j.config.springboot.starter.notify.ConfigModeNotifyConfigBuilder;
import cn.zzdt4j.config.springboot.starter.refresher.event.DynamicThreadPoolRefreshListener;
import cn.zzdt4j.config.springboot.starter.refresher.event.WebExecutorRefreshListener;
import cn.zzdt4j.config.springboot.starter.support.DynamicThreadPoolAdapterRegister;
import cn.zzdt4j.config.springboot.starter.support.DynamicThreadPoolConfigService;
import cn.zzdt4j.config.springboot.starter.support.DynamicThreadPoolPostProcessor;
import cn.zzdt4j.core.config.ApplicationContextHolder;
import cn.zzdt4j.core.enable.MarkerConfiguration;
import cn.zzdt4j.core.executor.handler.DynamicThreadPoolBannerHandler;
import cn.zzdt4j.core.extension.initialize.Zzdt4jDynamicThreadPoolInitializer;
import cn.zzdt4j.threadpool.alarm.api.ThreadPoolCheckAlarm;
import cn.zzdt4j.threadpool.alarm.handler.DefaultThreadPoolCheckAlarmHandler;
import cn.zzdt4j.threadpool.dynamic.model.config.properties.BootstrapConfigProperties;
import cn.zzdt4j.threadpool.message.api.NotifyConfigBuilder;
import cn.zzdt4j.threadpool.message.core.service.*;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.info.BuildProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Import;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

/**
 * Dynamic thread-pool auto-configuration
 *
 * @author by <a href="mailto:ligang941012@gmail.com">gang.Li</a>
 * @since 2023/9/15 0:25
 */
// @Configuration
@AutoConfiguration // 2.7 新增
@AllArgsConstructor
@ConditionalOnBean(MarkerConfiguration.Marker.class)
@EnableConfigurationProperties(SpringBootstrapConfigProperties.class)
@Import(ConfigHandlerConfiguration.class)
@ConditionalOnProperty(prefix = BootstrapConfigProperties.PREFIX, value = "enable", matchIfMissing = true, havingValue = "true")
public class DynamicThreadPoolAutoConfiguration {

    private final BootstrapConfigProperties bootstrapConfigProperties;

    @Bean
    @ConditionalOnMissingBean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public ApplicationContextHolder zzdt4jApplicationContextHolder() {
        return new ApplicationContextHolder();
    }

    @Bean
    @ConditionalOnMissingBean
    public NotifyConfigBuilder notifyConfigBuilder(AlarmControlHandler alarmControlHandler, WebThreadPoolService webThreadPoolService) {
        return new ConfigModeNotifyConfigBuilder(bootstrapConfigProperties, alarmControlHandler, webThreadPoolService);
    }

    @Bean
    @ConditionalOnMissingBean
    public ThreadPoolCheckAlarm defaultThreadPoolCheckAlarmHandler() {
        return new DefaultThreadPoolCheckAlarmHandler();
    }

    @Bean
    @ConditionalOnMissingBean
    public DefaultThreadPoolConfigChangeHandler defaultThreadPoolConfigChangeHandler(ThreadPoolSendMessageService threadPoolSendMessageService) {
        return new DefaultThreadPoolConfigChangeHandler(threadPoolSendMessageService);
    }

    @Bean
    @ConditionalOnMissingBean
    public WebThreadPoolConfigChangeHandler webThreadPoolConfigChangeHandler(BootstrapConfigProperties bootstrapConfigProperties,
                                                                             WebThreadPoolService webThreadPoolService,
                                                                             ThreadPoolSendMessageService zzdt4jSendMessageService) {
        if (bootstrapConfigProperties.getWeb() != null && StrUtil.isBlank(bootstrapConfigProperties.getWeb().getThreadPoolId())) {
            bootstrapConfigProperties.getWeb().setThreadPoolId(webThreadPoolService.getWebContainerType().getName());
        }
        return new WebThreadPoolConfigChangeHandler(zzdt4jSendMessageService);
    }

    /**
     * Registers the postprocessor for the dynamic thread-pool.
     *
     * @return DynamicThreadPoolPostProcessor
     */
    @Bean
    @ConditionalOnMissingBean
    @DependsOn("zzdt4jApplicationContextHolder")
    public DynamicThreadPoolPostProcessor dynamicThreadPoolPostProcessor() {
        return new DynamicThreadPoolPostProcessor(bootstrapConfigProperties);
    }

    @Bean
    @ConditionalOnMissingBean
    public DynamicThreadPoolRefreshListener zzdt4jExecutorListener(DefaultThreadPoolConfigChangeHandler threadPoolConfigChange,
                                                                   ConfigModeNotifyConfigBuilder configModeNotifyConfigBuilder,
                                                                   ThreadPoolBaseSendMessageService threadPoolBaseSendMessageService) {
        return new DynamicThreadPoolRefreshListener(threadPoolConfigChange, configModeNotifyConfigBuilder, threadPoolBaseSendMessageService);
    }

    @Bean
    @ConditionalOnMissingBean
    public WebExecutorRefreshListener zzdt4jWebExecutorRefreshListener(WebThreadPoolConfigChangeHandler threadPoolConfigChange) {
        return new WebExecutorRefreshListener(threadPoolConfigChange);
    }

    @Bean
    public DynamicThreadPoolAdapterRegister threadPoolAdapterRegister() {
        return new DynamicThreadPoolAdapterRegister(bootstrapConfigProperties);
    }

    @Bean
    @ConditionalOnMissingBean
    public DynamicThreadPoolBannerHandler dynamicThreadPoolBannerHandler(ObjectProvider<BuildProperties> buildProperties) {
        return new DynamicThreadPoolBannerHandler(bootstrapConfigProperties, buildProperties.getIfAvailable());
    }

    @Bean
    @ConditionalOnMissingBean
    public Zzdt4jDynamicThreadPoolInitializer zzdt4jDynamicThreadPoolInitializer() {
        return new Zzdt4jDynamicThreadPoolInitializer();
    }

    @Bean
    public DynamicThreadPoolConfigService dynamicThreadPoolConfigService() {
        return new DynamicThreadPoolConfigService();
    }
}
